/**
 * Copyright (c) 2020 wuchenxi
 * walter-blog is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * <p>
 * <p>
 * Mulan Permissive Software License，Version 2
 * <p>
 * Mulan Permissive Software License，Version 2 (Mulan PSL v2)
 * January 2020 http://license.coscl.org.cn/MulanPSL2
 */
package com.walter.auth.config;

import com.walter.auth.config.handler.MyAccessDeniedHandler;
import com.walter.auth.config.handler.MyFailHandler;
import com.walter.auth.config.handler.MyLogoutSuccessHandler;
import com.walter.auth.config.handler.MySuccessHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * spring security配置
 *
 * @author wuchenxi
 * @date 2021-06-01 08:23:30
 */
@Slf4j
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private DataSource dataSource;

    @Resource
    private PersistentTokenRepository jdbcTokenRepository;

    @Resource
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        log.info("init passwordEncoder");
        return new BCryptPasswordEncoder();
    }

    @Bean
    public PersistentTokenRepository jdbcTokenRepository() {
        log.info("init jdbcTokenRepository");
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        log.info("configure security");
        httpSecurity
                .authorizeRequests()
                // 需要放行的接口
//                .antMatchers("/user/**").permitAll()
//                .antMatchers("/content/**").permitAll()
                // 除了以上需要放行的请求路径外，其他接口访问都需要认证
                .anyRequest().permitAll()
                .and()
                .formLogin()
                // security框架默认只接收 username，password两个参数，
                // 如果前端给的不是这两个参数框架无法接收，具体原因参考类：org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter，
                // 这时候需要自定义这两个参数

                // 自定义用户名字段
                .usernameParameter("account")
                // 自定义密码字段
                .passwordParameter("password")
                // 登录接口url
                .loginProcessingUrl("/user/login")
                // 登录成功后跳转页面适配器
                .successHandler(new MySuccessHandler())
                // 登录失败后跳转页面适配器
                .failureHandler(new MyFailHandler())
                .and()
                .exceptionHandling()
                .accessDeniedHandler(new MyAccessDeniedHandler())
                .and()
                .rememberMe()
                .rememberMeParameter("rememberMe")
                .tokenRepository(jdbcTokenRepository)
                .tokenValiditySeconds(10080)
                .userDetailsService(userDetailsService)
                .and()
                .logout()
                .logoutUrl("/user/login_out")
                .logoutSuccessHandler(new MyLogoutSuccessHandler())
                .and()
                .cors()
                .and()
                .csrf().disable();
    }

}
